blank = " "*20

string_ip="IP:"
string_net="Net:"
string_batt="Batt:"
string_time="Time:"
    
class Line:
    def __init__(self, string_, child_, action_, clickable_):
        self.string = string_
        self.child = child_
        self.action = action_
        self.clickable = clickable_
        
class Page:
    def __init__(self, lines_, parent_):
        self.lines = lines_
        self.parent = parent_
    remembered_line = -1
    
# Creates enum from arguments:
#  >>> RealNumbers = enum('zero','one')
#  >>> print RealNumbers.one 
#  1
#
def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

# Turns a 2d array of [name, value] pairs into an enum of the names and a list of the pairs 
def organize(pairs):
    names = enum(*[entries[0] for entries in pairs])
    lines = [ Line(entries[1],entries[2],entries[3],entries[4]) for entries in pairs]
    return names, lines

def get_first_clickable_line(page):
    ind = 0
    for line in page.lines:
        if line.clickable == True: return ind
        ind = ind + 1
    return 0

    
import time

#     name,      string,          child,     action, clickable
main_menu_lines = [
    ['status',   "System status", None,      None, True],
    ['services', "Services",      None,      None, True]
    ]
MainMenu, lines = organize(main_menu_lines)
main_menu = Page(lines,None)

status_lines = [ 
    ['time',     string_time,     None,      None, False],
    ['batt_v',   string_batt,     None,      None, False],
    ['net',      string_net,      None,      None, False],
    ['ip',       string_ip,       None,      None, False]
    ]
Status, lines = organize(status_lines)
status = Page(lines,main_menu)

yes_no_lines = [
    ['action',   "",               None,      None, False],
    ['sure',     " are you sure?", None,      None, False],
    ['no',       "     No",        None,      None, True],
    ['yes',      "     Yes",       None,      None, True]
    ]
YesNo, lines = organize(yes_no_lines)
yes_no = Page(lines,None)

services_lines = [ 
    ['modem',    "Restart modem", yes_no,    "rmo", True],
    ['wview',    "Restart wview", yes_no,    "rwv", True],
    ['pc',       "Restart pc",    yes_no,    "rpc", True]
    ]
Service, lines = organize(services_lines)
services = Page(lines,main_menu)

main_menu.lines[0].child = status
main_menu.lines[1].child = services

current_page = main_menu
current_line = 0

funcdict = {}

display_dirty = True

def paint():
    global display_dirty
    display_dirty = True
    
def run_command(command):
    import subprocess
    try:
        result = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
    except:
        result = "Bad cmd!"
    return result.rstrip('\r\n') 
    
def init(print_line):
    funcdict[0] = print_line
    
def update_info(index):
    scripts="/home/pi/siweather/scripts"
    if index==99:
        run_command([scripts + "/date_to_file", "/tmp/lcd_tick"])
    if index==Status.ip or index==-1: 
        ip = run_command(scripts + "/getip")
        status.lines[Status.ip].string = "IP: " + ip
    if index==Status.batt_v or index==-1:
        batt = run_command(scripts + "/sunsaver_battv")
	status.lines[Status.batt_v].string = "Batt: " + batt + " V " 
    if index==Status.time or index==-1: 
        time = run_command(["date", "+%H:%M:%S %d/%m"])
        status.lines[Status.time].string = "Time: " + time
    
import threading
class UpdateDisplay(threading.Thread):
    def __init__(self):  
        threading.Thread.__init__(self)
    def run (self):
        while True:
            time.sleep(0.1)
            update_display()

update_disp_thread = UpdateDisplay()
update_disp_thread.setDaemon(True) # Without this the new thread continues when main thread is killed
update_disp_thread.start()

class UpdateTimer(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run (self):
        sec_tick = 0
        while True:
	    if current_page == status:         
                # Every two seconds...
                if sec_tick%2 == 0:
                    update_info(Status.time)
                # Every ten seconds
                if sec_tick%10 == 0:
                    update_info(Status.ip)
                    update_info(Status.batt_v)
		paint()
            if sec_tick >= 99999:
                sec_tick = 0
            time.sleep(1.0)
            update_info(99)
            sec_tick = sec_tick + 1
            
update_thread = UpdateTimer()
update_thread.setDaemon(True) # Without this the new thread continues when main thread is killed
update_thread.start()

def update_display():
    if not funcdict: # If no display method has been set up yet, return
        return
    global display_dirty
    if not display_dirty:
        return
    display_dirty = False
    k = 0
    global current_page
    global current_line
    for i in current_page.lines:
        if type(i.string) != str:
            funcdict[0](k, blank)
            k += 1
            continue
        if current_page.lines[current_line].clickable == False:
            funcdict[0](k, i.string)
        elif k == current_line:
            funcdict[0](k, ">" + i.string)
        else:
            funcdict[0](k, " " + i.string)            
        k += 1
    while k < 4:
        funcdict[0](k, blank)
        k += 1

def right():
    global current_page
    global current_line
    if (current_page.lines[current_line].clickable == False): return
        
    
        
    current_page.remembered_line = current_line
    
    if isinstance(current_page.lines[current_line].child, Page):
        if current_page.lines[current_line].child == yes_no:
            yes_no.parent = current_page
            yes_no.lines[YesNo.action].string = " " + current_page.lines[current_line].string + ","
            yes_no.lines[YesNo.no].child = current_page
            yes_no.lines[YesNo.yes].action = current_page.lines[current_line].action
            yes_no.remembered_line = YesNo.no
            
        current_page = current_page.lines[current_line].child
        if current_page.remembered_line == -1:
            current_page.remembered_line = get_first_clickable_line(current_page)
        current_line = current_page.remembered_line
        
        # If we've changed to status page, start thread to keep time live
        if current_page == status:
            update_info(-1)
            
        paint()
        return
        
    if type(current_page.lines[current_line].action) == str:
        print current_page.lines[current_line].action
        time.sleep(1)
        
def left():
    global current_page
    global current_line
    if (current_page.parent is None): 
        #print "no parent"
        #time.sleep(1)
        return
    current_page.remembered_line = current_line
    current_page = current_page.parent
    if current_page.remembered_line == -1:
            current_page.remembered_line = get_first_clickable_line(current_page)
    current_line = current_page.remembered_line
    paint()
    
def up():
    global current_line
    if current_line == 0: return
    if current_page.lines[current_line - 1].clickable == False: return
    current_line -= 1
    paint()
    
def down():
    global current_line
    if current_line == len(current_page.lines) - 1: return
    if current_page.lines[current_line + 1].clickable == False: return
    current_line += 1
    paint()
